import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:share_fit/app/helper/db/ute_db_helper.dart';
import 'package:share_fit/app/helper/ext/tr_ext.dart';
import 'package:share_fit/app/helper/gps_correct_helper.dart';
import 'package:share_fit/app/helper/storage_mixin.dart';
import 'package:share_fit/app/models/home/workout_model.dart';
import 'package:share_fit/app/models/sports/sport_detail_data.dart';
import 'package:share_fit/app/models/sports/sport_gps_data.dart';
import 'package:share_fit/app/models/sports/sport_state.dart';
import 'package:share_fit/app/models/sports/sports_model.dart';
import 'package:share_fit/app/routes/sports_routes.dart';
import 'package:share_fit/app/tools/Floating_util.dart';
import 'package:share_fit/app/tools/app_util.dart';
import 'package:share_fit/app/tools/date_tool.dart';
import 'package:share_fit/app/tools/log_utils.dart';
import 'package:share_fit/app/ute/uteped_const.dart';
import 'package:share_fit/app/ute/uteped_device.dart';
import 'package:share_fit/app/ute/uteped_helper.dart';
import 'package:share_fit/app/ute/uteped_mixin.dart';
import 'package:google_maps_flutter_android/google_maps_flutter_android.dart';
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
import 'package:share_fit/generated/locales.g.dart';
import 'package:uuid/uuid.dart';

class UTEPedSports with UTEPedMixin, StorageMixin implements UTEPedListener {
  int? _recordId;

  /// 记录是否是app发起的运动，默认是手表发起的运动
  bool _appSports = false;

  int _reqGpsCount = 0;

  /// 运动的开始时间
  int? _startTime;

  Timer? _setGpsTimer;

  /// 设备运动状态
  final SportState _deviceSportState = SportState();

  /// 实时定位
  StreamSubscription<Position>? positionStream;

  ///
  GoogleMapController? googleMapController;

  /// 实时上报数据
  SportsModel realTimeData = SportsModel();

  ///
  static UTEPedSports? _instance;

  /// 获取UTEPedSports的实例
  static UTEPedSports get instance => _instance!;

  /// 获取设备的运动状态
  SportState get sportState => _deviceSportState;

  /// 获取运动的唯一id
  int get recordId => _recordId ??= genRecordId();

  UTEPedSports._internal() {
    _instance = this;
    _init();
  }

  /// 初始化UTEPedSports单例，同时初始化地图
  factory UTEPedSports() => _instance ?? UTEPedSports._internal();

  void _init() {
    UTEPedHelper.addListener(this);

    initStorage();

    initMaps();
  }

  /// 生成运动记录的唯一id
  genRecordId() {
    return Uuid().hashCode;
  }

  /// 获取设备的运动状态
  getDeviceOperatorState() async {
    bool isConnected = await UTEPedDevice.instance.isConnected();
    if (isConnected) {
      Map stateMap = await dRemoteReq(UTEPedConst.methodGetDeviceOperatorState, {});
      onUpdateSportState(stateMap);
    }
  }

  @override
  String getRemotePath() {
    return UTEPedConst.pathSports;
  }

  @override
  Future<void> onRemoteEvent(event, method) async {
    Map map = event[UTEPedConst.keyValue];
    if (method == UTEPedConst.methodSetGpsParams) {
      onReceiveGpsNotify(map['isGpsEnable']);
    } else if (method == UTEPedConst.methodStartGpsSignal) {
      await getDeviceOperatorState();
      if (!_appSports && sportState.operatorType == 5) {
        FloatingUtil.openFloating(map['signal']);
      }
    }
  }

  /// 当APP端开启运动后，APP需要把一些必要的实时数据同步给设备端，比如运动时长等，否则设备端不会显示相应的数据。
  void onSetWorkoutRealTimeData(recMap) {
    realTimeData.fromRealTime(recMap);

    int duration = recMap['duration'];

    // 杰里手表不会上报时长，需要app自行计算
    _startTime ??= recMap['timeInfo'];
    if (duration == 0) {
      duration = int.parse(recMap['timeInfo'].toString()) - _startTime!;
      realTimeData.duration = duration;
    }

    recMap['workoutDuration'] = duration;
    recMap['realTimeHeartRate'] = recMap['heartRate'];
    recMap['operator'] = recMap['operatorType'];
    recMap['steps'] = recMap['step'];
    recMap['altitude'] = recMap['altitude'];
    recMap['stepCadence'] = recMap['cadence'];

    vRemoteReqAsync(UTEPedConst.methodSetWorkoutRealTimeData, {'map': recMap});
  }

  /// 保存已完成的运动记录
  void onSaveExerciseRecord(recMap, List<SportGpsData> gpsList, List<SportDetailData> detailList, List<int> strideList) {
    SportsModel rec = SportsModel();
    rec.from(recMap);

    if (!rec.isInvalidFromReportRecord()) {
      WorkoutModel wm = WorkoutModel.init();
      wm.fromSport(rec);
      wm.sportId = _recordId;

      saveNecessaryParams(wm, gpsList, detailList, strideList);

      UteDbHelper.getDB().then((db) => db.workoutDao.insertOne(wm));

      // 将运动结果数据和运动轨迹传递到结束页面
      Get.offNamed(SportsRoutes.motionEndPage, arguments: {
        'from': SportsRoutes.motionPage,
        'sportsResult': wm,
        'polyLine': Polyline(
          polylineId: PolylineId(_recordId.toString()),
          points: gpsList.map((e) => LatLng(e.gpsLatitude!, e.gpsLongitude!)).toList(),
          color: Colors.cyan,
          width: 5,
        ),
      });
    } else {
      Get.until((route) => route.settings.name == '/main');
    }

    /// 重置运动记录的唯一id
    _recordId = null;

    /// 清除开始时间
    _startTime = null;

    _appSports = false;
  }

  void saveNecessaryParams(WorkoutModel wm, List<SportGpsData> gpsList, List<SportDetailData> detailList, List<int> strideList) {
    wm.address = read(UTEPedConst.keyAddress, defaultValue: '', global: true);

    int pace = detailList.isEmpty ? 0 : detailList.map((e) => e.pace ?? 0).reduce((value, element) => value + element);
    wm.pace = detailList.isEmpty ? 0 : pace ~/ detailList.length;

    int heartRate = detailList.isEmpty ? 0 : detailList.map((e) => e.heartRate ?? 0).reduce((value, element) => value + element);
    wm.heart = detailList.isEmpty ? 0 : heartRate ~/ detailList.length;

    int altitude = detailList.isEmpty ? 0 : detailList.map((e) => e.elevation ?? 0).reduce((value, element) => value + element);
    wm.altitude = detailList.isEmpty ? 0 : altitude ~/ detailList.length;

    // 运动结束上报数据中没有步幅字段（注意：value['stride']是手动添加的字段），只能从实时上报数据中收集，再做平均
    wm.stride = strideList.isEmpty ? 0 : strideList.reduce((value, element) => value + element) ~/ strideList.length;

    wm.gpsDataList = jsonEncode([gpsList]);
    wm.detailDataList = jsonEncode(detailList);
  }

  /// 更新运动状态
  void onUpdateSportState(stateMap) {
    sportState.from(stateMap);

    logger2.d('sports state ${sportState.operatorType}');
    // if (!sportState.inProcess()) {
    //   sportState.monitorState = 0;
    // } else {
    //   sportState.monitorState = 1;
    // }
  }

  /// 下发定位给设备
  ///
  /// drawLineInMap 为false时，是设备主动请求gps，后台传给设备
  Future<void> onReceiveGpsNotify(bool isGpsEnable) async {
    if (isGpsEnable) {
      _reqGpsCount++;

      logger2.d('gps enable is true, request count $_reqGpsCount');
      FloatingUtil.openFloating(0);

      bool suc = await dRemoteReqAsync(UTEPedConst.methodStartGpsSignal, {});
      if (suc) {
        _setGpsTimer = Timer.periodic(const Duration(seconds: 2), (timer) {
          getCurrentLocation().then((pos) => onSetGpsParams(pos));
        });
      }
    } else {
      await dRemoteReqAsync(UTEPedConst.methodStopGpsSignal, {});
      FloatingUtil.closeAllFloating();
      _setGpsTimer?.cancel();
      _setGpsTimer = null;
      _reqGpsCount = 0;
    }
  }

  onSetGpsParams(Position position) {
    Map params = {
      'gpsLatitude': position.latitude,
      'gpsLongitude': position.longitude,
      'altitude': position.altitude.toInt(),
      'accuracy': position.accuracy,
    };
    vRemoteReqAsync(UTEPedConst.methodSetGpsParams, {'map': params});
  }

  checkLocationPermission() async {
    bool serviceEnabled;
    LocationPermission permission;

    // Test if location services are enabled.
    serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      // Location services are not enabled don't continue
      // accessing the position and request users of the
      // App to enable the location services.
      // return Future.error('Location services are disabled.');
      await Geolocator.openLocationSettings();
    }

    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        // Permissions are denied, next time you could try
        // requesting permissions again (this is also where
        // Android's shouldShowRequestPermissionRationale
        // returned true. According to Android guidelines
        // your App should show an explanatory UI now.
        // return Future.error('Location permissions are denied');
        await Geolocator.openLocationSettings();
      }
    }

    if (permission == LocationPermission.deniedForever) {
      // Permissions are denied forever, handle appropriately.
      // return Future.error('Location permissions are permanently denied, we cannot request permissions.');
      await Geolocator.openAppSettings();
    }
  }

  getLocationSettings() {
    late LocationSettings locationSettings;

    if (Platform.isAndroid) {
      locationSettings = AndroidSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: 1,
        timeLimit: const Duration(seconds: 10),
        forceLocationManager: true,
        intervalDuration: const Duration(seconds: 2),
        // //(可选)设置前台通知配置，使应用程序在进入后台时保持活跃
        // foregroundNotificationConfig: const ForegroundNotificationConfig(
        //   // notificationText:
        //   // "Example app will continue to receive your location even when you aren't using it",
        //   // notificationTitle: "Running in Background",
        //   enableWakeLock: true, notificationTitle: '', notificationText: '',
        // )
      );
    } else if (Platform.isIOS) {
      locationSettings = AppleSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: 1,
        timeLimit: const Duration(seconds: 10),
        pauseLocationUpdatesAutomatically: false,
        // 只有当我们的APP在后台启动时才设置为true
        showBackgroundLocationIndicator: false,
      );
    } else {
      locationSettings = const LocationSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: 1,
        timeLimit: Duration(seconds: 10),
      );
    }
    return locationSettings;
  }

  Future<Position> getCurrentLocation() async {
    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.
    // return await Geolocator.getCurrentPosition(
    //   desiredAccuracy: LocationAccuracy.best,
    //   forceAndroidLocationManager: Platform.isAndroid,
    //   timeLimit: const Duration(seconds: 20),
    // );

    Position? position;
    try {
      position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.bestForNavigation,
        timeLimit: const Duration(seconds: 2),
      );
    } catch (e, stackTrace) {
      position = await Geolocator.getLastKnownPosition();
    }
    return position ??
        await Geolocator.getCurrentPosition(
          desiredAccuracy: LocationAccuracy.bestForNavigation,
          timeLimit: const Duration(seconds: 2),
        );
  }

  StreamSubscription<Position> getLocationStream(Function listenCallback) {
    return Geolocator.getPositionStream(locationSettings: getLocationSettings()).listen((event) => listenCallback(event));
  }

  cancelLocation(StreamSubscription? positionStream) {
    if (positionStream != null) {
      positionStream.cancel();
      positionStream = null;
    }
  }

  addPolylineToMap(Position pos, Function addToMapCallback) {
    List<double> latLng = [0, 0];
    GpsCorrectHelper.transform(pos.latitude, pos.longitude, latLng);
    addToMapCallback(LatLng(latLng.first, latLng.last));
  }

  initMaps() {
    final GoogleMapsFlutterPlatform mapsImplementation = GoogleMapsFlutterPlatform.instance;
    if (mapsImplementation is GoogleMapsFlutterAndroid) {
      mapsImplementation.useAndroidViewSurface = true;
      initializeMapRenderer();
    }
  }

  /// Initializes map renderer to the `latest` renderer type for Android platform.
  ///
  /// The renderer must be requested before creating GoogleMap instances,
  /// as the renderer can be initialized only once per application context.
  Future<AndroidMapRenderer?> initializeMapRenderer() async {
    final Completer<AndroidMapRenderer?> completer = Completer<AndroidMapRenderer?>();
    WidgetsFlutterBinding.ensureInitialized();

    final GoogleMapsFlutterPlatform mapsImplementation = GoogleMapsFlutterPlatform.instance;
    if (mapsImplementation is GoogleMapsFlutterAndroid) {
      unawaited(mapsImplementation
          .initializeWithRenderer(AndroidMapRenderer.latest)
          .then((AndroidMapRenderer initializedRenderer) => completer.complete(initializedRenderer)));
    } else {
      completer.complete(null);
    }

    return completer.future;
  }

  double transDistance(distance) {
    int unit = read("space_unit_length", defaultValue: 0);
    if (unit == 0) {
      return distance * 1000;
    } else if (unit == 1) {
      return distance * 1609.34;
    }
    return 0;
  }

  /// 开始运动<br/><br/>
  /// distance单位为公里或者英里<br/>
  /// duration单位为妙<br/>
  /// calories单位为千卡<br/>
  start({int workoutType = 1, double distance = 0, int duration = 0, int calories = 0}) async {
    bool isConnected = await UTEPedDevice.instance.isConnected();
    if (!isConnected) {
      AppUtil.showTips(LocaleKeys.info.ts, LocaleKeys.device_not_connected.ts);
      return;
    }

    /// 启动运动之前先检查设备占用状态
    await getDeviceOperatorState();
    if (sportState.monitorState == null || sportState.monitorState == 0) {
      Get.toNamed(SportsRoutes.countDownPage)?.then((value) async {
        if (value) {
          // 开启手表运动数据上报
          // vRemoteReqAsync(UTEPedConst.methodSetIsOpenWorkoutOperatorReport, {});

          Map params = {
            'monitorState': 1,
            'sportType': 1,
            'workoutType': workoutType, // 运动类型 Motion type
            'operatorType': SportState.start,
            'forbidPause': true, // 是否允许手表控制手机暂停 1允许 0不允许
            'startTime': DateTool.getTimeInSeconds(DateTime.now()),
          };

          if (distance > 0) {
            params['distance'] = transDistance(distance);
          }
          if (duration > 0) {
            params['duration'] = duration * 60;
          }
          if (calories > 0) {
            params['calories'] = calories * 1000;
          }

          bool isConnected = await UTEPedDevice.instance.isConnected();
          if (isConnected) {
            vRemoteReqAsync(UTEPedConst.methodSetDeviceOperator, {'map': params});
          }

          sportState.monitorState = 1;

          /// 记录一次运动记录的id
          _recordId = genRecordId();
          _appSports = true;

          Get.toNamed(SportsRoutes.motionPage, arguments: {
            'workoutType': workoutType,
            'distance': distance,
            'duration': duration,
            'calories': calories,
          });
        }
      });
    } else {
      Fluttertoast.showToast(msg: LocaleKeys.sports_device_busy_in_motion_tip.ts, gravity: ToastGravity.TOP);
    }
  }

  /// 暂停运动
  pause() {
    // if (sportState.monitorState == 1) {
    // if (sportState.canPause()) {
    Map params = {
      'monitorState': 1,
      'operatorType': SportState.pause,
    };
    vRemoteReqAsync(UTEPedConst.methodSetDeviceOperator, {'map': params});
    // }
    // }
  }

  /// 停止运动
  stop() {
    if (realTimeData.isInvalidRealRecord()) {
      showCupertinoDialog(
        context: Get.context!,
        builder: (context) {
          return CupertinoAlertDialog(
            title: Text(LocaleKeys.info.ts),
            content: Text(LocaleKeys.sports_end_alert_text.ts),
            actions: [
              CupertinoDialogAction(
                  child: Text(LocaleKeys.ok.ts),
                  onPressed: () {
                    doFinish();
                    Get.back();
                  }),
              CupertinoDialogAction(
                isDestructiveAction: true,
                onPressed: () => Navigator.of(context).pop(),
                child: Text(LocaleKeys.cancel.ts),
              ),
            ],
          );
        },
      );
    } else {
      doFinish();
    }
  }

  doFinish() async {
    bool connected = await UTEPedDevice.instance.isConnected();
    if (connected) {
      /// 停止运动之前先将gps信号停止，避免app发起的运动也出现浮层
      vRemoteReqAsync(UTEPedConst.methodStopGpsSignal, {});
      Map params = {
        'monitorState': 0,
        'operatorType': SportState.finish,
      };
      vRemoteReqAsync(UTEPedConst.methodSetDeviceOperator, {'map': params});
    } else {
      // app未连接设备的状态下，也需要可以结束运动
      onSaveExerciseRecord({}, [], [], []);
    }

    // 关闭定位
    cancelLocation(positionStream);
  }

  /// 继续运动
  resume() {
    // if (sportState.monitorState == 1) {
    // if (sportState.canContinue()) {
    Map params = {
      'monitorState': 1,
      'operatorType': SportState.continuing,
    };
    vRemoteReqAsync(UTEPedConst.methodSetDeviceOperator, {'map': params});
    // }
    // }
  }
}
